#include "mainwindow.h"
#include "ui_mainwindow.h"




MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    serialPort=new QSerialPort(this);
    // 初始化定时器
    serialDataTimer = new QTimer(this);
    serialDataTimer->setInterval(10); // 设置超时时间为 10 毫秒
    serialDataTimer->setSingleShot(true); // 单次触发
    connect(serialDataTimer, &QTimer::timeout, this, &MainWindow::processSerialData);

    //信号与槽进行绑定
    connect(this, SIGNAL(msg_signal(QString)), this, SLOT(msg_show(QString)));
    connect(serialPort, &QSerialPort::readyRead, this, &MainWindow::readSerialData);
    //初始化操作
    ui->cb_serial->clear();
    //通过QSerialPortInfo查找可用串口
    foreach(const QSerialPortInfo &info, QSerialPortInfo::availablePorts())
    {
        ui->cb_serial->addItem(info.portName());
    }
}

MainWindow::~MainWindow()
{
    delete ui;
}





//重新检测串口
void MainWindow::on_bt_checkserial_clicked()
{
    // 清空串口下拉框
    ui->cb_serial->clear();

    // 获取可用串口信息
    QList<QSerialPortInfo> portList = QSerialPortInfo::availablePorts();

    // 如果没有检测到串口
    if (portList.isEmpty())
    {
        emit msg_signal("未检测到串口");
        return;
    }

    // 遍历所有可用串口
    foreach (const QSerialPortInfo &info, portList)
    {
        // 将串口名称添加到下拉框
        ui->cb_serial->addItem(info.portName());

        // 构建串口详细信息字符串
        QString portInfo;
        portInfo += "端口名称: " + info.portName() + "\n";
        portInfo += "描述: " + info.description() + "\n";
        portInfo += "制造商: " + info.manufacturer() + "\n";
        portInfo += "序列号: " + info.serialNumber() + "\n";
        portInfo += "系统位置: " + info.systemLocation() + "\n";
        portInfo += "供应商ID: " + (info.vendorIdentifier() ? QString::number(info.vendorIdentifier(), 16) : "未知") + "\n";
        portInfo += "产品ID: " + (info.productIdentifier() ? QString::number(info.productIdentifier(), 16) : "未知") + "\n";
        portInfo += "版本号: " + (info.hasVendorIdentifier() ? QString::number(info.vendorIdentifier(), 16) : "未知") + "\n";
        portInfo += "是否繁忙: " + QString(info.isBusy() ? "是" : "否") + "\n";
        // 发送串口信息到 UI 显示
        emit msg_signal(portInfo);
    }

    // 提示检测完成
    emit msg_signal("串口检测完成");
}

//打开串口
void MainWindow::on_bt_openserial_clicked()
{
    // 如果串口已经打开，则关闭串口
    if (serialPort->isOpen())
    {
        serialPort->close(); // 关闭串口
        emit msg_signal("串口已关闭");
        ui->bt_openserial->setText("打开串口"); // 更新按钮文本
        return;
    }

    // 获取串口名称
    QString portName = ui->cb_serial->currentText();
    if (portName.isEmpty())
    {
        emit msg_signal("打开失败：未选择串口");
        return;
    }

    // 获取波特率
    int baudRate = ui->cb_baud->currentText().toInt();

    // 获取数据位
    QSerialPort::DataBits dataBits = static_cast<QSerialPort::DataBits>(ui->cb_databit->currentText().toInt());

    // 获取停止位
    QSerialPort::StopBits stopBits = QSerialPort::OneStop; // 默认值
    QString stopBitText = ui->cb_stopbit->currentText();
    if (stopBitText == "1.5")
        stopBits = QSerialPort::OneAndHalfStop;
    else if (stopBitText == "2")
        stopBits = QSerialPort::TwoStop;

    // 获取校验位
    QSerialPort::Parity parity = QSerialPort::NoParity; // 默认值
    QString parityText = ui->cb_checkbit->currentText();
    if (parityText == "奇校验")
        parity = QSerialPort::OddParity;
    else if (parityText == "偶校验")
        parity = QSerialPort::EvenParity;

    // 配置串口
    serialPort->setPortName(portName); // 设置串口名称
    serialPort->setBaudRate(baudRate); // 设置波特率
    serialPort->setDataBits(dataBits); // 设置数据位
    serialPort->setStopBits(stopBits); // 设置停止位
    serialPort->setParity(parity);    // 设置校验位

    // 尝试打开串口
    if (serialPort->open(QIODevice::ReadWrite))
    {
        emit msg_signal("串口打开成功：" + portName);
        ui->bt_openserial->setText("关闭串口"); // 更新按钮文本
    }
    else
    {
        emit msg_signal("串口打开失败：" + serialPort->errorString());
    }
}

void MainWindow::on_bt_clearrecv_clicked()
{
    ui->tb_recv->clear();
}

void MainWindow::on_bt_send_clicked()
{
    // 检测串口是否打开
    if (!serialPort->isOpen())
    {
        emit msg_signal("发送失败：串口未打开");
        return;
    }

    // 获取发送内容
    QString sendData = ui->ed_send->toPlainText(); // 获取发送框中的内容
    if (sendData.isEmpty())
    {
        emit msg_signal("发送失败：发送内容为空");
        return;
    }

    // 判断是否以16进制发送
    QByteArray data;
    if (ui->chk_send_hex->isChecked())
    {
        // 将16进制字符串转换为字节数组
        QStringList hexList = sendData.split(' ');
        foreach (const QString &hex, hexList)
        {
            bool ok;
            char byte = static_cast<char>(hex.toInt(&ok, 16));
            if (ok)
            {
                data.append(byte);
            }
            else
            {
                emit msg_signal("发送失败：16进制格式错误");
                return;
            }
        }
    }
    else
    {
        // 直接以文本形式发送
        data = sendData.toUtf8();
    }

    // 判断是否在发送时换行


    // 发送数据
    qint64 bytesWritten = serialPort->write(data);
    if (bytesWritten == -1)
    {
        emit msg_signal("发送失败：" + serialPort->errorString());
    }
    else
    {
        emit msg_signal("发送成功：" + QString::number(bytesWritten) + " 字节");
    }

    // 判断是否开启定时发送
    if (ui->chk_send_auto->isChecked())
    {
        int interval = ui->chk_send_time->value(); // 获取定时发送间隔
        QTimer::singleShot(interval, this, &MainWindow::on_bt_send_clicked); // 定时发送
    }
}

void MainWindow::on_bt_clear_send_clicked()
{
    ui->ed_send->clear();
}

void MainWindow::msg_show(QString value)
{
    // 获取复选框的状态
    bool isHex = ui->chk_recv_hex->isChecked();       // 是否16进制显示
    bool isTimestamp = ui->chk_recv_time->isChecked(); // 是否显示时间戳
    bool isNewLine = ui->chk_rev_line->isChecked();    // 是否自动换行

    // 处理消息
    QString processedMsg = value;

    // 1. 16进制显示
    if (isHex)
    {
        QByteArray data = value.toUtf8(); // 将字符串转换为字节数组
        processedMsg = data.toHex(' ');    // 将字节数组转换为16进制字符串，以空格分隔
    }

    // 2. 显示时间戳
    if (isTimestamp)
    {
        QString timestamp = QDateTime::currentDateTime().toString("[yyyy-MM-dd hh:mm:ss] ");
        processedMsg = timestamp + processedMsg; // 在消息前添加时间戳
    }

    // 3. 自动换行
    if (isNewLine)
    {
        processedMsg += "\n"; // 在消息末尾添加换行符
    }

    // 将处理后的消息显示到 UI 控件中（假设使用 QPlainTextEdit 显示消息）
    ui->tb_recv->append(processedMsg);

}

// 修改 readSerialData 槽函数
void MainWindow::readSerialData()
{
    // 检查串口是否打开
    if (!serialPort->isOpen())
    {
        return;
    }

    // 读取所有可用数据并追加到缓冲区
    serialDataBuffer.append(serialPort->readAll());

    // 启动或重启定时器
    serialDataTimer->start();
}

void MainWindow::processSerialData()
{
    // 触发信号，传递完整数据
    emit msg_signal(serialDataBuffer);

    // 清空缓冲区
    serialDataBuffer.clear();
}
